package ui.classification;

import static preprocess.XMLContracter.ATTRIBUTE;
import static preprocess.XMLContracter.TEXT;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;

import org.dom4j.Document;
import org.dom4j.io.SAXReader;

import preprocess.Arith;
import preprocess.XMLContracter;

import classification.calcSimilarity.CalcSimilarityBySLVM;
import classification.classifier.ClassifyResult;
import classification.classifier.StreamClassifier;
import classification.classifier.StreamClassifierInfo;

import similarity.Similarity;
import similarity.SimpleTEDSimilarity;
import similarity.TextSimilarity;
import ui.xmlVisualization.XMLTree;
import utils.Configuration;
import utils.ResourceCritical;

public class ClaVisualFrame extends JInternalFrame implements Runnable
{
    /**
     * 
     */
    private static final long                  serialVersionUID = 3695425757605145754L;
    private static ArrayList<String>           similarityArray  = null;
    private static HashMap<String, Similarity> similarityMap    = null;
    private static ArrayList<Integer>   classNumArray = null;

    private JButton                            settingButton    = null;
    private JDialog                            settingDialog    = null;
    private JLabel                             classNumLabel    = null;
    private JComboBox                          classNumCombox   = null;
    private JLabel                             similarityLabel  = null;
    private JComboBox                          similarityCombox = null;
    private JLabel                             knnLabel         = null;
    private JTextField                         knnText          = null;
    private JButton                            startButton      = null;
    private JButton                            stopButton       = null;
    private ResourceCritical<Resource>         critical         = null;
    private JTable                             resultTable      = null;
    private JScrollPane                        scrollPane       = null;
    private JPanel                             panel            = null;

    private boolean                            isFinished       = false;
    private StreamClassifier                   classifier       = null;
    private String[]                           heads            = null;
    private String[]                           categories       = null;

    static
    {
        similarityArray = new ArrayList<String>();
        similarityMap = new HashMap<String, Similarity>();
        classNumArray = new ArrayList<Integer>();

        similarityArray.add("VSM");
        similarityMap.put("VSM", new TextSimilarity());
        similarityArray.add("TED");
        similarityMap.put("TED", new SimpleTEDSimilarity());
        similarityArray.add("SLVM");
        similarityMap.put("SLVM", new CalcSimilarityBySLVM());
        
        classNumArray.add(2);
        classNumArray.add(4);
        classNumArray.add(8);
        classNumArray.add(16);
    }

    public ClaVisualFrame()
    {
        super("XML 流分类窗口(双击查看DOM树)", true, false, true, true);
        init();
    }

    private void init()
    {
        this.setSize(new Dimension(800, 600));
        this.settingButton = getSettingButton();
        this.add(this.settingButton, BorderLayout.SOUTH);
        this.setCritical(new ResourceCritical<Resource>(1000));
        this.setVisible(true);
    }

    private JButton getSettingButton()
    {
        if (this.settingButton == null)
        {
            this.settingButton = new JButton("打开分类设置窗口");
            this.settingButton.addActionListener(new ActionListener()
            {
                @Override
                public void actionPerformed(ActionEvent e)
                {
                    getSettingDialog().setVisible(true);
                }
            });
        }
        return this.settingButton;
    }

    private JTable getResultTable()
    {
        JTable table = new JTable();
        return table;
    }

    private JDialog getSettingDialog()
    {
        if (this.settingDialog == null)
        {
            /* 三个设置窗口 */
            this.classNumLabel = new JLabel("请选择待分类类别数目");
            this.classNumLabel.setHorizontalAlignment(JLabel.RIGHT);
            this.classNumCombox = new JComboBox();
            for(Integer classNum : classNumArray)
            {
                this.classNumCombox.addItem(classNum);
            }

            this.similarityLabel = new JLabel("请选择相似度量模型");
            this.similarityLabel.setHorizontalAlignment(JLabel.RIGHT);
            this.similarityCombox = new JComboBox();
            for (String similarity : similarityArray)
            {
                this.similarityCombox.addItem(similarity);
            }

            this.knnLabel = new JLabel("请设置KNN数目");
            this.knnLabel.setHorizontalAlignment(JLabel.RIGHT);
            this.knnText = new JTextField();

            /* 启动和停止按钮 */
            this.startButton = new JButton("开始分类");
            this.startButton.addActionListener(new StartButtonActionListener(
                    this));
            this.stopButton = new JButton("停止分类");
            this.stopButton
                    .addActionListener(new StopButtonActionListener(this));

            /* 设置对话框 */
            this.settingDialog = new JDialog();
            GridLayout layout = new GridLayout(4, 2, 20, 20);
            this.settingDialog.setLayout(layout);

            /* 添加对话框选项 */
            this.settingDialog.add(this.classNumLabel);
            this.settingDialog.add(this.classNumCombox);
            this.settingDialog.add(this.similarityLabel);
            this.settingDialog.add(this.similarityCombox);
            this.settingDialog.add(this.knnLabel);
            this.settingDialog.add(this.knnText);
            this.settingDialog.add(this.startButton);
            this.settingDialog.add(this.stopButton);
            this.settingDialog.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
            Dimension size = new Dimension(300, 200);
            Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
            Point location = new Point((int) (screenSize.getWidth() - size
                    .getWidth()) / 2, (int) (screenSize.getHeight() - size
                    .getHeight()) / 2);
            this.settingDialog.setSize(size);
            this.settingDialog.setLocation(location);
            this.settingDialog.setResizable(false);
        }
        return this.settingDialog;
    }

    public JComboBox getClassNumCombox()
    {
        return this.classNumCombox;
    }

    public JTextField getknnText()
    {
        return this.knnText;
    }

    public JComboBox getSimilarityCombox()
    {
        return this.similarityCombox;
    }

    public HashMap<String, Similarity> getSimilarityMap()
    {
        return similarityMap;
    }

    public void setClassifier(StreamClassifier classifier)
    {
        this.classifier = classifier;
    }

    public void setFinished(boolean isFinished)
    {
        this.isFinished = isFinished;
    }

    /**
     * @return the critical
     */
    public ResourceCritical<Resource> getCritical()
    {
        return critical;
    }

    /**
     * @param critical
     *            the critical to set
     */
    public void setCritical(ResourceCritical<Resource> critical)
    {
        this.critical = critical;
    }

    public void setEnable(boolean enabled)
    {
        this.classNumCombox.setEnabled(enabled);
        this.knnText.setEnabled(enabled);
        this.similarityCombox.setEnabled(enabled);
        this.startButton.setEnabled(enabled);
        this.stopButton.setEnabled(!enabled);
    }

    public void run()
    {
        this.categories = this.classifier.getCategoryIDs();

        while (!isFinished)
        {
            Resource r = this.critical.pop();
            ClassifyResult result = this.classifier.classify(r.getStreams(), r
                    .getName());
            HashMap<String, Double> similarityArray = result
                    .getSimilarityArray();

            if (this.resultTable == null)
            {
//                DefaultTableColumnModel tcm = new DefaultTableColumnModel();
//                DefaultTableCellRenderer dtcr = new DefaultTableCellRenderer();
//                TableColumn tc = new TableColumn();
//                
//                dtcr.setBackground(Color.yellow);
//                tc.setHeaderValue("文件名");
//                tc.setHeaderRenderer(dtcr);
//                tcm.addColumn(tc);
//                tc = new TableColumn();
//                tc.setHeaderValue("预测类别");
//                tc.setHeaderRenderer(dtcr);
//                tcm.addColumn(tc);
//                
//                for(String value: this.categories)
//                {
//                    tc = new TableColumn();
//                    tc.setHeaderValue("与类别 " + value + " 相似度");
//                    tc.setHeaderRenderer(dtcr);
//                    tcm.addColumn(tc);
//                }
//
//                JTableHeader header = new JTableHeader(tcm);
//                this.resultTable = new JTable();
//                this.resultTable.setTableHeader(header);
                
                
                /* 设置初始表格 */
                Vector<String> vector = new Vector<String>();
                vector.add("文件名");
                vector.add("预测类别");

                for (String value : this.categories)
                {
                    vector.add("与类别 " + value + " 相似度");
                }

                DefaultTableModel dtm = new DefaultTableModel(null, vector)
                {
                    private static final long serialVersionUID = 1522824467049784518L;

                    public boolean isCellEditable(int row, int col)
                    {
                        return false;
                    }
                };

                this.resultTable = new JTable(dtm);
                this.resultTable
                        .addMouseListener(new JTableMouseClickedListener(
                                this.resultTable));
                JTableHeader header = this.resultTable.getTableHeader();
                DefaultTableCellRenderer dtcr = new DefaultTableCellRenderer();
                dtcr.setBackground(Color.yellow);
                header.setDefaultRenderer(dtcr);
                this.resultTable.setTableHeader(header);

                Container cp = this.getContentPane();
                JScrollPane scrollPane = new JScrollPane(this.resultTable);
                cp.add(scrollPane, BorderLayout.CENTER);
                this.resultTable.setVisible(true);
                this.updateUI();
            }

            /* 添加当前处理文件分类信息 */
            String fileName = r.getName();
            String category = result.getCategory();

            DefaultTableModel tableModel = (DefaultTableModel) this.resultTable
                    .getModel();
            String[] row = new String[this.resultTable.getTableHeader()
                    .getColumnModel().getColumnCount()];
            row[0] = fileName;
            row[1] = category;

            for (int index = 0; index < this.categories.length; index++)
            {
                String key = this.categories[index];
                if (similarityArray.containsKey(key))
                {
                    row[index + 2] = Arith.round(similarityArray.get(key), 4)
                            + "";
                }
                else
                {
                    row[index + 2] = "0.0";
                }
            }
            tableModel.addRow(row);
            this.resultTable.setVisible(true);
        }
    }
}

class StartButtonActionListener implements ActionListener
{
    private ClaVisualFrame frame = null;

    public StartButtonActionListener(ClaVisualFrame frame)
    {
        this.frame = frame;
    }

    @Override
    public void actionPerformed(ActionEvent e)
    {
        try
        {
            final ClaVisualFrame frame = this.frame;

            boolean succ = true;

            int classNum = -1;
            int knnNum = -1;
            Similarity similarity = null;

            if (frame.getClassNumCombox().getSelectedIndex() == -1)
            {
                succ = false;
                new ErrorDialog("待分类数设置出错");
            }
            if (frame.getknnText().getText().isEmpty())
            {
                succ = false;
                new ErrorDialog("KNN数目设置出错");
            }
            if (frame.getSimilarityCombox().getSelectedIndex() == -1)
            {
                succ = false;
                new ErrorDialog("相似度量方式设置出错");
            }

            if (!succ)
            {
                return;
            }
            else
            {
                classNum = Integer.parseInt(frame.getClassNumCombox()
                        .getSelectedItem().toString());
                knnNum = Integer.parseInt(frame.getknnText().getText().trim());

                similarity = frame.getSimilarityMap().get(
                        frame.getSimilarityCombox().getSelectedItem());

                StreamClassifierInfo info = new StreamClassifierInfo(classNum,
                        knnNum, similarity);
                StreamClassifier classifier = new StreamClassifier(info);

                /* 启动获取XML流文件的线程 */
                new ResourceGetter(frame.getCritical()).start();

                this.frame.setEnable(false);
                this.frame.setFinished(false);
                this.frame.setClassifier(classifier);

                /* 创建分类运行的线程，并启动 */
                new Thread(frame).start();
            }
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }
    }
}

class StopButtonActionListener implements ActionListener
{
    private ClaVisualFrame frame = null;

    public StopButtonActionListener(ClaVisualFrame frame)
    {
        this.frame = frame;
    }

    @Override
    public void actionPerformed(ActionEvent e)
    {
        // TODO Auto-generated method stub
        ClaVisualFrame frame = this.frame;
        frame.setFinished(true);
        frame.setEnable(true);
    }
}

class JTableMouseClickedListener implements MouseListener
{
    private JTable               table    = null;
    private static SAXReader     reader   = null;
    private static XMLContracter contract = null;
    protected final String       ROOT     = Configuration.RootPath;

    static
    {
        reader = new SAXReader();
        contract = new XMLContracter();
    }

    public JTableMouseClickedListener(JTable table)
    {
        this.table = table;
    }

    @Override
    public void mouseClicked(MouseEvent e)
    {
        // TODO Auto-generated method stub
        if (e.getButton() == MouseEvent.BUTTON1)
        {
            if (e.getClickCount() == 2)
            {
                int rowIndex = this.table.getSelectedRow();
                int colIndex = 0;
                String selectFileName = this.table.getModel().getValueAt(
                        rowIndex, colIndex).toString();

                try
                {
                    ArrayList<File> files = new ArrayList<File>();
                    getFile(new File(ROOT), files, selectFileName + ".xml");
                    final Document doc = reader.read(files.get(0));
                    contract.contract(doc, ATTRIBUTE | TEXT);
                    new Thread()
                    {
                        public void run()
                        {
                            XMLTree.showTree(doc);
                        }
                    }.start();
                }
                catch (Exception ex)
                {
                    ex.printStackTrace();
                }
            }
        }
    }

    private void getFile(File path, ArrayList<File> files, String fileName)
    {
        if (files.size() != 0)
            return;

        for (File f : path.listFiles())
        {
            if (f.isDirectory())
                getFile(f, files, fileName);
            else if (f.getName().equals(fileName))
            {
                files.add(f);
                return;
            }
        }
    }

    @Override
    public void mouseEntered(MouseEvent arg0)
    {
        // TODO Auto-generated method stub

    }

    @Override
    public void mouseExited(MouseEvent arg0)
    {
        // TODO Auto-generated method stub

    }

    @Override
    public void mousePressed(MouseEvent arg0)
    {
        // TODO Auto-generated method stub

    }

    @Override
    public void mouseReleased(MouseEvent arg0)
    {
        // TODO Auto-generated method stub

    }

}

class ErrorDialog extends JDialog
{
    /**
     * 
     */
    private static final long serialVersionUID = -6847304774552388186L;
    private String            errMsg;

    public ErrorDialog(String errMsg)
    {
        this.errMsg = errMsg;
        showErrMsg();
    }

    private void showErrMsg()
    {
        JTextField errorText = new JTextField(this.errMsg);
        this.add(errorText);
        this.setVisible(true);
    }
}
